//
// Created by chaofengan on 23-8-28.
//

#ifndef UNTITLED6_BUDDY_STRUCT_H
#define UNTITLED6_BUDDY_STRUCT_H

#include "stdio.h"
#include <unordered_map>
#include "math.h"
#include "vector"
#include "log_system.h"

class Node{
public:
    int data;
    Node *next;

public:
    Node(int num){
        data = num;
        next = nullptr;
    }
};
class Link{
public:
    Node *head;
    int data;
    Link *next;
public:
    Link(int size){
       head = new Node(size);
       head->next = nullptr;
       data = size;
       next = nullptr;
    }

    void push_back(int data){
        Node* tem_point = head;
        while(tem_point->next != nullptr){
            tem_point = tem_point->next;
        }
        Node *new_node = new Node(data);
        tem_point->next = new_node;
    }
    void push_in_order(int data){
        if(head->next == nullptr){
            Node* tem = new Node(data);
            head->next = tem;
            return;
        }
        Node* tem_point = head->next;
        Node* last_point = head;
        while(tem_point != nullptr){
            if(tem_point->data > data){

            }
            tem_point = tem_point->next;
        }
        Node *new_node = new Node(data);
        tem_point->next = new_node;
    }

};
class Free_links{
public:
    Link* link_head;

public:
    Free_links(int link_nums,com_Kb_int min_num){
        link_head = new Link(link_nums);
        int max_num = log(min_num)/log(2) + link_nums;
        Link* total_link_point = link_head;
        for(int i = 0;i < link_nums;i++){
            int now_num = max_num - i - 1;
            Link* tem_link = new Link(now_num);
            total_link_point->next = tem_link;
            total_link_point = total_link_point->next;
        }
    }
    void show(){
        std::cout << "here are free links:" << std::endl;
        std::cout << "total_links_num = " << link_head->data << std::endl;
        Link* range_point = link_head->next;
        while (range_point != nullptr){
            std::cout << "2^" << range_point->data << "Kb blocks:" ;
            Node* node_point = range_point->head->next;
            while (node_point != nullptr){
                printf("%d ",node_point->data);
                node_point = node_point->next;
            }
            std::cout << std::endl;
            range_point = range_point->next;
        }
    }
};
class Buddy_heap{
public:
    int *datas;
    int length;

public:
    Buddy_heap(int max_size){
        length = max_size;
        datas = new int[max_size];
    }
};

class total_buddy_struct{
public:
    Free_links* freeLinks;
    exp_int total_memory_size;//这个用指数表示（如512M是2^19kb,这个值就是19）
    exp_int heap_use_size;//同上，也是指数，单位也是kb。
    int heap_height;
    exp_int page_size;
    int link_num;//空闲链表的数量，不算哨兵。
    memory_use_log* memoryUseLog;
    process_using_table* com_process_using_table;
public:
    total_buddy_struct(com_Mb_int memory_size,com_Kb_int single_page_size){//memory_size表示内存大小，单位是Mb，single_page_size单位是Kb。
        total_memory_size = 10+log(memory_size)/log(2);
        page_size = log(single_page_size)/log(2);
        heap_use_size = pow(2,total_memory_size - page_size+1);
        heap_height = total_memory_size - page_size+1;
        link_num = heap_height;
        freeLinks = new Free_links(heap_height,single_page_size);
        freeLinks->link_head->next->push_in_order(1);
        memoryUseLog = new memory_use_log;
        com_process_using_table = new process_using_table;
    }
    void apply_for_memory(int pid,com_Kb_int want_memory_amount){
        exp_int block_size = ceil(log(want_memory_amount)/log(2));//最适合的空闲块大小。也是指数表示的。
        int have_free_block_link_num;
        Link* last_have_free_block_link = search_min_free_link_point_with_min_limit(block_size);
        Link* want_size_link = search_appropriate_link_point_by_num(block_size);

        if(last_have_free_block_link == nullptr){
            std::cout << "error:no appropriate free block!" << std::endl;
            return;
        }

        if(want_size_link == last_have_free_block_link){
            int give_position = want_size_link->head->next->data;
            memoryUseLog->add_apply_log(pid, want_memory_amount, give_position);
            want_size_link->head->next = want_size_link->head->next->next;
            single_memory_using_record s1(pid,APPLY,want_memory_amount,give_position);
            com_process_using_table->add_using(s1);
            return;
        }else{
            int give_position = last_have_free_block_link->head->next->data;
            last_have_free_block_link->head->next = last_have_free_block_link->head->next->next;
            Link* link_point = last_have_free_block_link;
            while (link_point != want_size_link){
                link_point = link_point->next;
                link_point->push_in_order(give_position + pow(2,link_point->data));
            }
            memoryUseLog->add_apply_log(pid, want_memory_amount, give_position);
            single_memory_using_record s1(pid,APPLY,want_memory_amount,give_position);
            com_process_using_table->add_using(s1);
        }
    }

    void release_memory(int pid,int block_position){
        if(search_if_can_release(pid,block_position)){


            
            memoryUseLog->add_release_log(pid,block_position,*com_process_using_table);
        }else{
            std::cout << "release error!" << std::endl;
        }
    }
    void show_free_links(){
        freeLinks->show();
    }
    void show_mem_log(){
        memoryUseLog->show_all();
    }
private:
    Link* search_appropriate_link_point_by_num(exp_int head_num){
        Link* loop_link_point = freeLinks->link_head;
        while (loop_link_point != nullptr){
            if(loop_link_point->data == head_num){
                return loop_link_point;
            }
            loop_link_point = loop_link_point->next;
        }
        return nullptr;
    }

    Link* search_max_free_link_point(){
        Link* loop_link_point = freeLinks->link_head;
        while (loop_link_point != nullptr){
            if(loop_link_point->head->next != nullptr){
                return loop_link_point;
            }
            loop_link_point = loop_link_point->next;
        }
        return nullptr;
    }
    Link* search_min_free_link_point_with_min_limit(exp_int min_limit){
        Link* loop_link_point = freeLinks->link_head;
        Link* solution = nullptr;
        while (loop_link_point != nullptr){
            if(loop_link_point->head->next != nullptr and loop_link_point->data >= min_limit){
                solution = loop_link_point;
            }
            if(loop_link_point->data < min_limit){
                break;
            }
            loop_link_point = loop_link_point->next;
        }
        return solution;
    }

    bool search_if_can_release(int pid,int block_position){
        if(com_process_using_table->get_amount_by_pid_and_position(pid,block_position) == NO_AMOUNT){
            return false;
        }
        return true;
    }



};
#endif //UNTITLED6_BUDDY_STRUCT_H
